//
// Author: Vladimir Migashko <migashko@gmail.com>, (C) 2011
//
// Copyright: See COPYING file that comes with this distribution
//

#ifndef HITLIST_RN_JSON_ASPECT_HPP
#define HITLIST_RN_JSON_ASPECT_HPP

#include <fas/filter/binary_filter.hpp>
#include <fas/adv/ad_cleaner.hpp>
#include <fas/adv/io/ad_binary_splitter.hpp>
#include <fas/aop/aspect.hpp>
#include <fas/adv/json_rpc3/aspect.hpp>
#include "json_aspect.hpp"

namespace ap = ::fas::pattern;
namespace ad = ::fas::adv;
namespace adio = ::fas::adv::io;
namespace aa = ::fas::aop;
namespace af = ::fas::filter;
namespace ajr = ::fas::adv::json_rpc3;

/** @brief тег для ad_rn_writer */
struct _rn_writer_{};

/** @brief адвайс аспекта соединения
 *
 * добаляет '\r\n' к исходящим данным
 */
class ad_rn_writer
{
  typedef std::vector<char> data_type;
  data_type data;
public:
  template<typename T>
  void operator () (T&t, const char* d, size_t s)
  {
    /// Возможно не самое красивое решения, но при s < 1024 (очень примерно)
    /// Это работает быстрее чем запись двумя порциями ( d, а затем '\r\n')
    data.reserve(s + 2);
    data.assign(d, d + s);
    data.push_back('\r');
    data.push_back('\n');
    /// отправляем на запись
    t.get_aspect().template get<af::_writer_>()(t, &(data[0]), data.size());

    if ( data.capacity() > 10240 )
      data_type().swap(data);
  }
};


/// Разделяет входящий поток по rn
typedef aa::advice<
           aa::tag_list_n< af::_on_read_, aa::gtag< ad::_cleaner_> >::type,
           /// Разделенные данные кидаем на вход json-rpc аспекта
           adio::ad_binary_splitter< adio::sep<'\r', '\n'>, ajr::_input_ >
         >
rn_reader_advice;

typedef aa::advice<
    aa::tag< _rn_writer_ >,
    ad_rn_writer
  >
rn_writer_advice;

typedef ap::type_list_n<
    rn_reader_advice,
    rn_writer_advice,
    /// связываем "выход" аспекта json-rpc (ajr::_output_) с ad_rn_writer
    aa::alias< _rn_writer_, ajr::_output_ >
>::type advice_list;

/// Этот аспект разделяет входные данные по \r\n символам и добавляет их к исходящим данным 
typedef aa::aspect<advice_list> rn_aspect;

/// Объединяем аспекты json-rpc и rn-аспекта
typedef aa::aspect_merge< json_aspect, rn_aspect>::type  rn_json_aspect;

#endif
